/*
 * ﻿Copyright (C) 2013 NewMain Softech
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.newmainsoftech.eatestutil.ejbtestutil;

import java.text.ChoiceFormat;
import java.text.MessageFormat;

import javax.ejb.EJBException;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Abstract aspect to dump root cause exceptions of EJB exception (during test) since stackframe being 
 * shown at EJB exception sometimes misses showing critical cause exception by suppressing it. <br />
 * Sub-aspect class must override <code>{@link #pointcutAtEjbExceptionIssuer()}</code> abstract method 
 * with annotating <code>&#x40;Pointcut</code>.
 * 
 * @author Arata Y.
 */
@Aspect
public abstract class AbstractDumpEjbRootExceptionAspect {
	Logger logger = LoggerFactory.getLogger( this.getClass());
		Logger getLogger() {
			return logger;
		}
	void logException( final MethodSignature methodSignature, final Throwable throwable) {
		Logger logger = getLogger();
		final String methodName = methodSignature.getName();
		final MessageFormat messageFormat 
		= new MessageFormat( 
				"Dumping root cause at {0} in exception stackframe from "
				.concat( methodName).concat( " method"));
			final String[] depthMessage 
			= { "top exception frame", 
				"1st depth exception frame", 
				"2nd depth exception frame", 
				"3rd depth exception frame", 
				"{0}th depth exception frame"};
			final ChoiceFormat choiceFormat 
			= new ChoiceFormat( new double[]{ 0, 1, 2, 3, 4}, depthMessage);
			messageFormat.setFormatByArgumentIndex( 0, choiceFormat);
		int depth = 0;
		Throwable rootCause  = throwable;
		for( Throwable cause = throwable.getCause(); cause != null; cause = cause.getCause()) {
			rootCause = cause;
			depth++;
		} // for
		logger.info( messageFormat.format( new Object[]{ depth}), rootCause);
	}
	
	/**
	 * To provide pointcut for specifying scope of catching <code>EJBException</code>.
	 */
	@Pointcut
	public abstract void pointcutAtEjbExceptionIssuer();
	
	/**
	 * <code>AfterThrowing</code> advise to log root cause of <code>EJBException</code> caught 
	 * in <code>Pointcut</code> given by <code>{@link #pointcutAtEjbExceptionIssuer()}</code> method. 
	 * 
	 * @param joinPoint
	 * @param throwable
	 */
	@AfterThrowing( pointcut = "pointcutAtEjbExceptionIssuer()", throwing = "throwable")
	public void throwingAfterExecutionOfTestMethod( JoinPoint joinPoint, Throwable throwable) {
		if ( throwable instanceof EJBException) {
			Logger logger = getLogger();
				if ( logger.isInfoEnabled()) {
					logException( (MethodSignature)joinPoint.getSignature(), throwable);
				}
		}
	}
}